home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_400 / 424_01 / ed_157 / calculate.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-03-20  |  11.5 KB  |  503 lines

  1. /*
  2.  * Copyright (C) 1992 by Rush Record
  3.  * Copyright (C) 1993 by Charles Sandmann (sandmann@clio.rice.edu)
  4.  * 
  5.  * This file is part of ED.
  6.  * 
  7.  * ED is free software; you can redistribute it and/or modify it under the terms
  8.  * of the GNU General Public License as published by the Free Software Foundation.
  9.  * 
  10.  * ED is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
  11.  * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
  12.  * PARTICULAR PURPOSE.  See the GNU General Public License for more details.
  13.  * 
  14.  * You should have received a copy of the GNU General Public License along with ED
  15.  * (see the file COPYING).  If not, write to the Free Software Foundation, 675
  16.  * Mass Ave, Cambridge, MA 02139, USA.
  17.  */
  18. #include "opsys.h"
  19.  
  20. #include <stdio.h>
  21. #include <stddef.h>
  22. #include <string.h>
  23. #include <math.h>
  24.  
  25. #include "ctyp_dec.h"
  26.  
  27. #ifndef PI
  28. #define PI 3.14159265
  29. #endif
  30. #define CONV (PI / 180.0)
  31.  
  32. #ifndef HUGE_VAL           /* ANSI type definition conversion */
  33. #define HUGE_VAL HUGE
  34. #endif
  35.  
  36. /******************************************************************************\
  37. |Routine: calculate
  38. |Callby: command
  39. |Purpose: Implements a basic calculator.
  40. |Arguments:
  41. |    buf is a buffer containing an algebraic expression.
  42. |    result is the returned buffer containing the answer, or an error message.
  43. \******************************************************************************/
  44. Int calculate(pbuf,result)
  45. Char *pbuf;
  46. Char *result;
  47. {
  48.     static Char *buf = NULL;
  49.     static Int bufl = 0;
  50.     static Int maxtokens = 0;
  51.     static Int *token = NULL;
  52.     static double *value,*real_value;
  53.     static Char *intrinsic[] =
  54.     {
  55.         "sinh","cosh","tanh",
  56.         "sind","cosd","tand",
  57.         "cotd","secd","cscd",
  58.         "sin","cos","tan",
  59.         "cot","sec","csc",
  60.         "arcsind","arccosd","arctand",
  61.         "arcsin","arccos","arctan",
  62.         "sqrt","fact","exp","ln","log","int","abs",
  63.     };
  64.  
  65.     Char *p,*q,c;
  66.     double val;
  67.     Int i,j,ival;
  68.     Int ntokens,nintr,depth,lowest,first,second,operator;
  69.  
  70. /* ignore empty expressions */
  71.     if(!pbuf)
  72.         goto empty;
  73. /* expand the local buffer if necessary */
  74.     if((i = strlen(pbuf) + 2) > bufl)
  75.     {
  76.         if(buf)
  77.             ifree(buf);
  78.         buf = (Char *)imalloc((bufl = i) * sizeof(Char));
  79.     }
  80. /* copy to local buffer, making it lowercase */
  81.     for(p = pbuf,q = buf;(c = *p) && c != '=';p++)
  82.         *q++ = tolower(c);
  83.     *q++ = ' ';
  84.     *q = '\0';
  85. /* get the number of tokens */
  86.     nintr = sizeof(intrinsic)/sizeof(intrinsic[0]);    /* number of intrinsic functions */
  87.     for(ntokens = 0,p = buf;(c = *p);p++)
  88.         switch(c)
  89.         {
  90.             case '(': case ')': case '+': case '-': case '*': case '/': case '^':
  91.                 ntokens++;
  92.                 break;
  93.             case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '.':
  94.                 if(my_sscanf(p,"%Lf%n",&val,&i) != 1)
  95.                 {
  96.                     strcpy(result,"Bad number.");
  97.                     return(0);
  98.                 }
  99.                 p += i - 1;
  100.                 ntokens++;
  101.                 break;
  102.             case ' ': case '\t':
  103.                 break;
  104.             default:
  105.                 for(i = 0;i < nintr;i++)
  106.                 {
  107.                     if(!strncmp(p,intrinsic[i],strlen(intrinsic[i])))
  108.                     {
  109.                         ntokens++;
  110.                         break;
  111.                     }
  112.                 }
  113.                 if(i == nintr)
  114.                 {
  115.                     strcpy(result,"Bad function.");
  116.                     return(0);
  117.                 }
  118.                 p += strlen(intrinsic[i]) - 1;
  119.                 ntokens++;
  120.         }
  121. /* this is an entry point for a spot below where closing parens need to be added to the token array */
  122. expand_tokens:
  123.     if((ntokens += 2) > maxtokens)    /* add two for enclosing parens */
  124.     {
  125.         if(token)
  126.         {
  127.             ifree(token);
  128.             ifree(real_value);
  129.         }
  130.         maxtokens = ntokens;
  131.         token = (Int *)imalloc(maxtokens * sizeof(int));
  132. /* value is a double-aligned version of real_value. real_value is kept around for later freeing */
  133.         real_value = (double *)imalloc((maxtokens + 1) * sizeof(double));
  134.         value = (double *)((((size_t)real_value) + 7) & ~7);
  135.     }
  136.     token[0] = '(';    /* enclose entire expression in parens */
  137.     ntokens = 1;    /* first paren is first token */
  138. /*
  139.     convert string to tokens.
  140.     token[i] = 0 if token is a number. In this case, value[i] is the numeric value.
  141.     token[i] = <character> if token is an operator <+ - * / ( )>.
  142.     token[i] = -n if token is intrinsic function #n (starting with #1).
  143. */
  144.     for(p = buf;(c = *p);p++)
  145.         switch(c)
  146.         {
  147.             case '(': case ')': case '+': case '-': case '*': case '/': case '^':
  148.                 token[ntokens++] = c;
  149.                 break;
  150.             case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '.':
  151.                 token[ntokens] = 0;
  152.                 my_sscanf(p,"%Lf%n",value + ntokens++,&i);
  153.                 p += i - 1;
  154.                 break;
  155.             case ' ': case '\t':
  156.                 break;
  157.             default:
  158.                 for(i = 0;i < nintr;i++)
  159.                 {
  160.                     if(!strncmp(p,intrinsic[i],strlen(intrinsic[i])))
  161.                     {
  162.                         token[ntokens++] = -1 - i;
  163.                         break;
  164.                     }
  165.                 }
  166.                 p += strlen(intrinsic[i]) - 1;
  167.         }
  168. /* finish with enclosing parenthesis */
  169.     token[ntokens++] = ')';
  170. /* now process the tokens, always going to deepest paren depth */
  171.     while(ntokens > 1)
  172.     {
  173.         for(lowest = depth = i = 0;i < ntokens;i++)
  174.         {
  175.             if(token[i] == '(')
  176.             {
  177.                 if(++depth > lowest)
  178.                 {
  179.                     lowest = depth;
  180.                     first = i;
  181.                 }
  182.             }
  183.             else if(token[i] == ')')
  184.             {
  185.                 if(--depth < 0)
  186.                 {
  187.                     strcpy(result,"Bad parentheses.");
  188.                     return(0);
  189.                 }
  190.             }
  191.         }
  192. /* make parentheses balance if they don't */
  193.         if(depth)
  194.         {
  195.             if(ntokens + depth > maxtokens)
  196.             {
  197.                 ntokens += depth;
  198.                 goto expand_tokens;
  199.             }
  200.             while(depth-- > 0)
  201.                 token[ntokens++] = ')';
  202.             continue;
  203.         }
  204. /* find closure of lowest expression */
  205.         for(second = first + 1;token[second] != ')';second++);
  206. /* evaluate the expression */
  207.         if((i = first + 1) == second)
  208.             value[first] = 0;
  209.         else
  210.         {
  211.             if(token[i] == '-')
  212.             {
  213.                 val = -value[++i];
  214.                 i++;
  215.             }
  216.             else
  217.                 val = value[i++];
  218.             while(i < second)
  219.             {
  220.                 switch(token[i++])
  221.                 {
  222.                     case 0:
  223.                         strcpy(result,"Two numbers with no operator between.");
  224.                         return(0);
  225.                     case '+':
  226.                         operator = 0;
  227.                         break;
  228.                     case '-':
  229.                         operator = 1;
  230.                         break;
  231.                     case '*':
  232.                         operator = 2;
  233.                         break;
  234.                     case '/':
  235.                         operator = 3;
  236.                         break;
  237.                     case '^':
  238.                         operator = 4;
  239.                         break;
  240.                     default:
  241.                         operator = token[i-1];
  242.                         break;
  243.                 }
  244.                 if(i == second)
  245.                 {
  246.                     strcpy(result,"Operator not followed by number.");
  247.                     return(0);
  248.                 }
  249.                 switch(token[i])
  250.                 {
  251.                     case 0:
  252.                         switch(operator)
  253.                         {
  254.                             case 0:
  255.                                 val += value[i];
  256.                                 break;
  257.                             case 1:
  258.                                 val -= value[i];
  259.                                 break;
  260.                             case 2:
  261.                                 val *= value[i];
  262.                                 break;
  263.                             case 3:
  264.                                 if(!value[i])
  265.                                 {
  266.                                     strcpy(result,"Divide by zero.");
  267.                                     return(0);
  268.                                 }
  269.                                 val /= value[i];
  270.                                 break;
  271.                             case 4:
  272.                                 if((val == 0 && value[i] <= 0) || (val < 0 && floor(value[i]) != value[i]))
  273.                                 {
  274.                                     strcpy(result,"Illegal exponentiation.");
  275.                                     return(0);
  276.                                 }
  277.                                 val = pow(val,value[i]);
  278.                                 break;
  279.                         }
  280.                         break;
  281.                     default:
  282.                         strcpy(result,"Two operators with no number between.");
  283.                         return(0);
  284.                 }
  285.                 i++;
  286.             }
  287. /* check for preceeding intrinsic function(s) */
  288.             i = first;
  289.             while(i > 0)
  290.             {
  291.                 if(token[i - 1] >= 0)
  292.                     break;
  293.                 switch(-token[--i])
  294.                 {
  295.                     case 1:
  296.                         if(fabs(val) > log(HUGE_VAL))
  297.                         {
  298.                             strcpy(result,"Bad hyperbolic sine.");
  299.                             return(0);
  300.                         }
  301.                         val = sinh(val);
  302.                         break;
  303.                     case 2:
  304.                         if(fabs(val) > log(HUGE_VAL))
  305.                         {
  306.                             strcpy(result,"Bad hyperbolic cosine.");
  307.                             return(0);
  308.                         }
  309.                         val = cosh(val);
  310.                         break;
  311.                     case 3:
  312.                         val = tanh(val);
  313.                         break;
  314.                     case 4:
  315.                         val = sin(CONV * val);
  316.                         break;
  317.                     case 5:
  318.                         val = cos(CONV * val);
  319.                         break;
  320.                     case 6:
  321.                         if(val - (double)(90 * (int)(val/90.0)) == 0 && (int)(val/90.0) & 1)
  322.                         {
  323.                             strcpy(result,"Bad tangent.");
  324.                             return(0);
  325.                         }
  326.                         val = tan(CONV * val);
  327.                         break;
  328.                     case 7:
  329.                         if(val - (double)(90 * (int)(val/90.0)) == 0 && !((int)(val/90.0) & 1))
  330.                         {
  331.                             strcpy(result,"Bad cotangent.");
  332.                             return(0);
  333.                         }
  334.                         val = 1.0/tan(CONV * val);
  335.                         break;
  336.                     case 8:
  337.                         if(val - (double)(90 * (int)(val/90.0)) == 0 && (int)(val/90.0) & 1)
  338.                         {
  339.                             strcpy(result,"Bad secant.");
  340.                             return(0);
  341.                         }
  342.                         val = 1.0/cos(CONV * val);
  343.                         break;
  344.                     case 9:
  345.                         if(val - (double)(90 * (int)(val/90.0)) == 0 && !((int)(val/90.0) & 1))
  346.                         {
  347.                             strcpy(result,"Bad cosecant.");
  348.                             return(0);
  349.                         }
  350.                         val = 1.0/sin(CONV * val);
  351.                         break;
  352.                     case 10:
  353.                         val = sin(val);
  354.                         break;
  355.                     case 11:
  356.                         val = cos(val);
  357.                         break;
  358.                     case 12:
  359.                         if(val - (double)(90 * (int)(val/90.0)) == 0 && (int)(val/90.0) & 1)
  360.                         {
  361.                             strcpy(result,"Bad tangent.");
  362.                             return(0);
  363.                         }
  364.                         val = tan(val);
  365.                         break;
  366.                     case 13:
  367.                         if(val - (double)(90 * (int)(val/90.0)) == 0 && !((int)(val/90.0) & 1))
  368.                         {
  369.                             strcpy(result,"Bad cotangent.");
  370.                             return(0);
  371.                         }
  372.                         val = 1.0/tan(val);
  373.                         break;
  374.                     case 14:
  375.                         if(val - (double)(90 * (int)(val/90.0)) == 0 && (int)(val/90.0) & 1)
  376.                         {
  377.                             strcpy(result,"Bad secant.");
  378.                             return(0);
  379.                         }
  380.                         val = 1.0/cos(val);
  381.                         break;
  382.                     case 15:
  383.                         if(val - (double)(90 * (int)(val/90.0)) == 0 && !((int)(val/90.0) & 1))
  384.                         {
  385.                             strcpy(result,"Bad cosecant.");
  386.                             return(0);
  387.                         }
  388.                         val = 1.0/sin(val);
  389.                         break;
  390.                     case 16:
  391.                         if(val < -1.0 || val > 1.0)
  392.                         {
  393.                             strcpy(result,"Bad arcsin.");
  394.                             return(0);
  395.                         }
  396.                         val = asin(val) / CONV;
  397.                         break;
  398.                     case 17:
  399.                         if(val < -1.0 || val > 1.0)
  400.                         {
  401.                             strcpy(result,"Bad arccos.");
  402.                             return(0);
  403.                         }
  404.                         val = acos(val) / CONV;
  405.                         break;
  406.                     case 18:
  407.                         val = atan(val) / CONV;
  408.                         break;
  409.                     case 19:
  410.                         if(val < -1.0 || val > 1.0)
  411.                         {
  412.                             strcpy(result,"Bad arcsin.");
  413.                             return(0);
  414.                         }
  415.                         val = asin(val);
  416.                         break;
  417.                     case 20:
  418.                         if(val < -1.0 || val > 1.0)
  419.                         {
  420.                             strcpy(result,"Bad arccos.");
  421.                             return(0);
  422.                         }
  423.                         val = acos(val);
  424.                         break;
  425.                     case 21:
  426.                         val = atan(val);
  427.                         break;
  428.                     case 22:
  429.                         if(val < 0.0)
  430.                         {
  431.                             strcpy(result,"Square root of negative value.");
  432.                             return(0);
  433.                         }
  434.                         val = sqrt(val);
  435.                         break;
  436.                     case 23:
  437.                         if(val <= -1.0)
  438.                         {
  439.                             strcpy(result,"Factorial of negative value.");
  440.                             return(0);
  441.                         }
  442.                         else if(val >= 34.0)
  443.                         {
  444.                             strcpy(result,"Factorial of value that is too large.");
  445.                             return(0);
  446.                         }
  447.                         for(ival = (int)val,val = 1.0;ival > 0;ival--)
  448.                             val *= (double)ival;
  449.                         break;
  450.                     case 24:
  451.                         if(fabs(val) > log(HUGE_VAL))
  452.                         {
  453.                             strcpy(result,"Bad exponentiation.");
  454.                             return(0);
  455.                         }
  456.                         val = exp(val);
  457.                         break;
  458.                     case 25:
  459.                         if(val <= 0.0)
  460.                         {
  461.                             strcpy(result,"Log of non-positive value.");
  462.                             return(0);
  463.                         }
  464.                         val = log(val);
  465.                         break;
  466.                     case 26:
  467.                         if(val <= 0.0)
  468.                         {
  469.                             strcpy(result,"Log(base 10) of non-positive value.");
  470.                             return(0);
  471.                         }
  472.                         val = log10(val);
  473.                         break;
  474.                     case 27:
  475.                         val = (double)((int)val);
  476.                         break;
  477.                     case 28:
  478.                         val = (val < 0.0)? -val : val;
  479.                         break;
  480.                 }    /* end of intrinsic switch */
  481.             }    /* end of while */
  482.             first = i;
  483.         }    /* end of if(second = first + 1) */
  484. /* replace token[first] with 0, value[first] with val, squeeze out everything up to second inclusive */
  485.         token[first] = 0;
  486.         value[first] = val;
  487.         for(i = second + 1,j = first + 1;i < ntokens;i++,j++)
  488.         {
  489.             token[i - second + first] = token[i];
  490.             value[i - second + first] = value[i];
  491.         }
  492.         ntokens = j;
  493. /* go for another pass */
  494.     }    /* end of while(ntokens > 1) */
  495. /* report results */
  496.     sprintf(result,"%f",value[0]);
  497.     return(1);
  498. empty:
  499.     strcpy(result,"Nothing to calculate.");
  500.     return(0);
  501. }
  502.  
  503.